home *** CD-ROM | disk | FTP | other *** search
- Path: fido.asd.sgi.com!austern
- From: kanze@gabi-soft.fr (J. Kanze)
- Newsgroups: comp.std.c++
- Subject: Re: sample auto_ptr template
- Date: 10 Apr 1996 09:56:31 PDT
- Organization: GABI Software, Sarl.
- Approved: austern@isolde.mti.sgi.com
- Message-ID: <KANZE.96Apr10111407@gabi.gabi-soft.fr>
- References: <009A04DA6A831C40.49800EAC@ittpub.nl>
- <bill-0504961003150001@bgibbons.vip.best.com> <4k4noe$igl@jabba.lehman.com>
- <bill-0804960932250001@bgibbons.vip.best.com> <4kcr2d$p03@jabba.lehman.com>
- NNTP-Posting-Host: isolde.mti.sgi.com
- X-Original-Date: 10 Apr 1996 09:14:07 GMT
- In-Reply-To: ajay@lehman.com's message of 09 Apr 1996 09:58:11 PDT
- X-Auth: PGPMoose V1.1 PGP comp.std.c++
- iQBVAwUBMWvoQUy4NqrwXLNJAQENFgH+LlqUvSg907kaiS3v8Pma5kwpx5m1OjFd
- 9Evfclq1BXxJ65gXKfg9OPuJfxxIFX3iAB1Eh0NYEl2eL1tZQv8E8w==
- =DiuH
- Originator: austern@isolde.mti.sgi.com
-
- In article <4kcr2d$p03@jabba.lehman.com> ajay@lehman.com (Ajay Kamdar)
- writes:
-
- |> In article <bill-0804960932250001@bgibbons.vip.best.com>,
- |> Bill Gibbons <bill@gibbons.org> wrote:
- |> >In article <4k4noe$igl@jabba.lehman.com>, ajay@lehman.com (Ajay Kamdar) wrote:
- |> >
- |> [ snip ]
- |> >>
- |> >> What's wrong with this? It doesn't require copy semantics
- |> >> for auto_ptr. Yet both the caller and the callee
- |> >> are exception safe and there is no loss of clarity.
- |> >
- |> >The problem is that it requires handling the raw pointer.
- |> >Any time you transfer ownership by using release() to extract
- |> >the raw pointer and then later use the raw pointer to
- |> >construct another auto_ptr, there is a window where there is
- |> >no exception safety.
- |> >
-
- |> You didn't say whether the example I gave was exception
- |> safe or not.
-
- But I did. It's not.
-
- |> To reiterate the main points of the example
- |> + The caller directly initializes an auto_ptr with
- |> the returned value from the calee.
- |> auto_ptr<X> ptr(get_X());
-
- |> + The callee releases the pointer from it's own
- |> auto_ptr in it's return statement.
-
- |> No copy constructors are involved in the return. Hence
- |> there is no possibility of an exception thrown from
- |> a user defined copy constructor. So which window are
- |> you referring to during which there is no exception
- |> safety? I claim there is none.
-
- The destructors of any local variables in get_X.
-
- |> >Of course you can carefully craft the code to make sure that
- |> >no exceptions can be propagated during the window. But there
- |> >are two problems:
-
- |> The example I gave is straight forward C++ programming; no
- |> contortions or careful coding are required. The coding
- |> pattern is simple enough that even junior programmers can
- |> be taught to follow it easily.
-
- The only real solution I can think of to be 100% exception safe would be
- to write get_X as follows:
-
- T*
- get_X()
- {
- auto_ptr< T > localTmp ;
- {
- // All of the work here, including assigning the actual
- // pointer to localTmp, and above all, all local variables
- // except localTmp here.
- }
- return localTmp.release() ;
- }
-
- While the pattern isn't that complicated, it is certainly not what we
- are used to, and is likely to be forgotten from time to time.
-
- |> Many other more useful extensions have been voted down by
- |> the commitee on the grounds that the requested extension
- |> could be implemented by existing mechanisms within the
- |> language, even if those techniques required a fair
- |> amount of work for the programmer. That stance cannot be
- |> more applicable than in the case of the copy semantics
- |> of auto_ptr -- there is simply no need for such semantics
- |> because identical exception safety can be achieved by
- |> a simple coding pattern.
-
- I imagine that the committee is more tolerant with regards to extensions
- which are purely library issues. Library issues are almost guaranteed
- by their very nature not to have a surprise side effect in other parts
- of the language.
-
- |> > (1) The maintainers of the code may not be as careful about
- |> > exception safety. When everything is handled by
- |> > auto_ptr the risk of bugs creeping in is smaller. Such
- |> > bugs are very difficult to find by testing.
-
- |> Let's analyze which code is more difficult to maintain
- |> and difficult to debug -- one using the copy semantics
- |> of auto_ptr or one wihout copy semantics of auto_ptr.
-
- |> With copy semantics
- |> ===================
- |> If the copy ctor of auto_ptr taking a const auto_ptr&
- |> releases its raw pointer by casting away const,
- |> a programmer can accidentaly "lose" the raw pointer from
- |> within an auto_ptr -- even if the programmer was working
- |> with a const auto_ptr. This occurrs because auto_ptr
- |> violates const correctness and releases the raw pointer
- |> from the raw object.
-
- |> If the copy ctor of the auto_ptr taking a const auto_ptr&
- |> takes ownership of the raw pointer by casting away const
- |> and setting a flag (the latest proposal), the programmer
- |> can end up with a dangling pointer in the original
- |> auto_ptr if the new auto_ptr destructs first and deletes
- |> the raw pointer.
-
- |> It is possible that even extensive testing may not
- |> uncover such a problem on a less frequently traversed
- |> path in the code. Even if the path is traversed during
- |> testing, an error may or may not be generated when using
- |> the dangling pointer. Hence it is very possible that the
- |> error might escape it to production code.
-
- I think the question here is one of patterns. The auto_ptr is designed
- to implement simply certain basic, frequently occuring patterns. If it
- is used for other things, it is unsafe.
-
- Because its only legitimate use *is* these frequently occuring patterns,
- any other use is easily detected by code review. The alternative, using
- raw pointers, is more dangerous, because raw pointers have so many uses;
- the error is not immediately apparent.
-
- |> Without copy semantics of auto_ptr
- |> ==================================
- |> By eliminating any surprises due to the standard
- |> auto_ptr violating const correctness and leaving
- |> behind dangling pointers, program correctness is
- |> actually *improved*.
-
- |> But for the moment assume that even the simple pattern
- |> of using auto_ptr (release() on return in callee,
- |> direct initialization of auto_ptr in caller) is
- |> not followed correctly in some situation. Two major
- |> scenarios are possible:
- |> 1. The error happens on a frequently travesed path
- |> in the code, resulting in frequent ommission to
- |> call delete.
-
- |> In such situations, any of the many good leak
- |> detectors on the market will show the error
- |> during testing. The error will be fixed
- |> before it reached production.
-
- |> 2. The error is rare enough that it occurs only in
- |> production.
-
- |> By definition, the error is rare. So the application
- |> will lose some resource each time. In practice,
- |> each occurence of a failure to delete a resource is
- |> not disastorous on its own, and the application will
- |> go on.
-
-
- |> So which one is better for the C++ programmer? An approach
- |> which can lead to disastorous surprises at run-time
- |> (auto_ptr with copy semantics approach) definitely does
- |> not look the right choice under any stretch of imagination.
-
- In short, you are suggesting that memory leaks are OK, as long as they
- don't occur too often. This isn't the case for my applications.
-
- |> > (2) The interface of get_X does not implicitly document
- |> > that the returned pointer refers to an object which
- |> > should be automatically deleted on an exception.
- |> ^^^^^^^^^^^^^^^^^^^^^^^
-
- |> Now we are getting close to what I firmly believe is the
- |> real driving reason behind the push for auto_ptr to
- |> have copy semantics.
-
- |> Note that in the above quoted text, the reference to
- |> exceptions in "deleted on an exception" is irrelevant.
- |> In this case, the caller must always delete the ptr
- |> allocated by the callee() -- exception or no exception.
- |> Hence the use of auto_ptr in this case has nothing to
- |> do with exception safety. But it has everything to do
- |> with trying to replace documentation accompanying
- |> get_X() saying that the caller must delete the pointer.
-
- No. The caller cannot possibly delete the pointer, since the pointer is
- never assigned at the caller side if an exception occurs. The caller
- never even sees the pointer.
-
- The whole point of the copy semantics is that there is a period of time
- after the evaluation of the return value in the return statement when
- neither the callee nor the caller have access to the pointer. Using a
- temporary class object means, however, that this object does have
- access, and can delete the object if an exception is thrown. The
- alternative is somehow to ensure that no exception can be thrown. This
- is not always trivial.
-
- |> In isolation, it is a good goal to replace comments
- |> which prescribe certain behavior with code constructs
- |> which automatically take care of the issue. By
- |> giving copy semantics to auto_ptr, the need to
- |> document transfer of ownership of pointer is sourght
- |> to be eliminated. I firmly believe that *this* is the
- |> real reason behind the copy semantics of auto_ptr, with
- |> exception safety only a peripheral issue at best.
- |> Unfortunately, it is abundantly clear that this attempt
- |> at replacing documentation by giving auto_ptr copy
- |> semantics has pretty high costs.
-
- There are two separate problems: the unexpected semantics of assignment,
- and the exception safety. Because of the way the language is defined,
- we can only define auto_ptr to handle one correctly; the other must be
- left to comments. (I think that we more or less agree up until this
- point.) The question is: which one?
-
- IMHO, requiring the programmer to handle the exception safety is
- non-intuitive, difficult, and error prone. While I agree that requiring
- the programmer to handle the strange copy semantics is non-intuitive, it
- is relatively easy to check. In all *valid* uses of auto_ptr, an
- auto_ptr which is copied should immediately go out of scope. This is
- trivially true in the case of source functions, like get_X. The only
- point which requires a little bit of attention is when copying to a
- sink; I would generally try and arrange my code so that the call to the
- sinking function is the last thing in the block in which the auto_ptr
- was declared, but I'm not certain that this is always possible or
- natural. (In practice, until now, it has always been the most natural
- way of writing the code anyway.)
-
- Any attempts to assign between two declared auto_ptr's, or to initialize
- an auto_ptr with another declared auto_ptr, should be caught by code
- review.
-
- |> I strongly urge those who can do something about this
- |> (those on the committee) to step back and separate
- |> the wheat from the chaff. Don't make auto_ptr harder
- |> to use for *all* C++ programmers by allowing it to
- |> have copy semantics. Make a separate class
- |> (taligent_ptr) which has the copy semantics for
- |> those who *choose* to use it, rather than forcing
- |> everyone to program with an unfortunate choice.
-
- I believe that John Skaller had a proposal with something like six
- different pointer types. The committee found this a little too
- complicated for its likings (I would agree), and settled on defining two
- (or maybe three).
-
- For various reasons, it was unable to find a definition of counted_ptr
- which would obtain a concensus. In some ways, this is regrettable, but
- if you look at the implementations of this class in Barton and Nackman,
- on one hand, and Meyers II on the other, you can see that in fact, there
- are contradictory goals to be met. I have no problem understanding why
- no concensus could be reached.
-
- In the case of auto_ptr, those (like Bill Gibbons) with extensive
- practical experience actually using such a pointer indicated that to be
- useful, it needed copy semantics. (I might add that this corresponds
- exactly to my experience.) Without copy semantics, it simply wouldn't
- be used in most cases. (Or programmers would resort to tricks such as
- returning the pointer as a raw pointer, with the resulting loss of
- exception safety.)
- --
- James Kanze (+33) 88 14 49 00 email: kanze@gabi-soft.fr
- GABI Software, Sarl., 8 rue des Francs Bourgeois, 67000 Strasbourg, France
- Conseils en informatique industrielle --
- -- Beratung in industrieller Datenverarbeitung
- ---
- [ comp.std.c++ is moderated. To submit articles: Try just posting with your
- newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
- comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
- Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
- Comments? mailto:std-c++-request@ncar.ucar.edu
- ]
-